{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "github地址:[https://github.com/cheesezh/python_design_patterns](https://github.com/cheesezh/python_design_patterns)\n",
    "\n",
    "## 题目1\n",
    "用程序模拟股民直接炒股的代码，比如股民投资了股票1，股票2，股票3，国债1，房地产1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "买入股票1\n",
      "买入股票2\n",
      "买入股票3\n",
      "买入国债1\n",
      "买入房地产1\n",
      "卖出股票1\n",
      "卖出股票2\n",
      "卖出股票3\n",
      "卖出国债1\n",
      "卖出房地产1\n"
     ]
    }
   ],
   "source": [
    "class Stock1():\n",
    "    def sell(self):\n",
    "        print(\"卖出股票1\")\n",
    "    def buy(self):\n",
    "        print(\"买入股票1\")\n",
    "        \n",
    "class Stock2():\n",
    "    def sell(self):\n",
    "        print(\"卖出股票2\")\n",
    "    def buy(self):\n",
    "        print(\"买入股票2\")\n",
    "        \n",
    "class Stock3():\n",
    "    def sell(self):\n",
    "        print(\"卖出股票3\")\n",
    "    def buy(self):\n",
    "        print(\"买入股票3\")\n",
    "        \n",
    "class NationalDebt1():\n",
    "    def sell(self):\n",
    "        print(\"卖出国债1\")\n",
    "    def buy(self):\n",
    "        print(\"买入国债1\")\n",
    "        \n",
    "class Realty1():\n",
    "    def sell(self):\n",
    "        print(\"卖出房地产1\")\n",
    "    def buy(self):\n",
    "        print(\"买入房地产1\")\n",
    "        \n",
    "def user_action():\n",
    "    \"\"\"\n",
    "    模拟股民的操作，股民需要了解各个理财产品的走势，进而买入卖出\n",
    "    \"\"\"\n",
    "    gu1 = Stock1()\n",
    "    gu2 = Stock2()\n",
    "    gu3 = Stock3()\n",
    "    nd1 = NationalDebt1()\n",
    "    rt1 = Realty1()\n",
    "    \n",
    "    gu1.buy()\n",
    "    gu2.buy()\n",
    "    gu3.buy()\n",
    "    nd1.buy()\n",
    "    rt1.buy()\n",
    "    \n",
    "    gu1.sell()\n",
    "    gu2.sell()\n",
    "    gu3.sell()\n",
    "    nd1.sell()\n",
    "    rt1.sell()\n",
    "    \n",
    "user_action()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 题目2\n",
    "用程序模拟股民通过基金理财的代码，股民只需要购买&卖出基金即可，不需要对具体的股票等有了解."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "买入股票1\n",
      "买入股票2\n",
      "买入股票3\n",
      "买入国债1\n",
      "买入房地产1\n",
      "卖出股票1\n",
      "卖出股票2\n",
      "卖出股票3\n",
      "卖出国债1\n",
      "卖出房地产1\n"
     ]
    }
   ],
   "source": [
    "class Fund():\n",
    "    def __init__(self):\n",
    "        self.gu1 = Stock1()\n",
    "        self.gu2 = Stock2()\n",
    "        self.gu3 = Stock3()\n",
    "        self.nd1 = NationalDebt1()\n",
    "        self.rt1 = Realty1()\n",
    "        \n",
    "    def sell(self):\n",
    "        self.gu1.sell()\n",
    "        self.gu2.sell()\n",
    "        self.gu3.sell()\n",
    "        self.nd1.sell()\n",
    "        self.rt1.sell()\n",
    "    \n",
    "    def buy(self):\n",
    "        self.gu1.buy()\n",
    "        self.gu2.buy()\n",
    "        self.gu3.buy()\n",
    "        self.nd1.buy()\n",
    "        self.rt1.buy()\n",
    "        \n",
    "def user_action():\n",
    "    \"\"\"\n",
    "    模拟股民的操作，股民只需要买进卖出基金即可\n",
    "    \"\"\"\n",
    "    fund = Fund()\n",
    "    \n",
    "    fund.buy()\n",
    "    \n",
    "    fund.sell()\n",
    "    \n",
    "user_action()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 外观模式\n",
    "\n",
    "外观模式，为子系统中的一组接口提供一个一致的界面，此模式定义了一个高层接口，这个接口使得这一子系统更加容易使用[DP]。\n",
    "\n",
    "### 多个子系统类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SubSystemOne():\n",
    "    def method_one(self):\n",
    "        print(\"子系统方法1\")\n",
    "        \n",
    "class SubSystemTwo():\n",
    "    def method_two(self):\n",
    "        print(\"子系统方法2\")\n",
    "        \n",
    "class SubSystemThree():\n",
    "    def method_three(self):\n",
    "        print(\"子系统方法3\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 外观类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "子系统方法1\n",
      "子系统方法2\n",
      "子系统方法2\n",
      "子系统方法3\n"
     ]
    }
   ],
   "source": [
    "class Facade():\n",
    "    def __init__(self):\n",
    "        self.one = SubSystemOne()\n",
    "        self.two = SubSystemTwo()\n",
    "        self.three = SubSystemThree()\n",
    "        \n",
    "    def method_a(self):\n",
    "        self.one.method_one()\n",
    "        self.two.method_two()\n",
    "        \n",
    "    def method_b(self):\n",
    "        self.two.method_two()\n",
    "        self.three.method_three()\n",
    "\n",
    "def main():\n",
    "    facade = Facade()\n",
    "    \n",
    "    facade.method_a()\n",
    "    \n",
    "    facade.method_b()\n",
    "    \n",
    "main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 点评\n",
    "外观模式完美的体现了依赖倒转原则和迪米特法则的思想，是非常常用的模式之一。\n",
    "\n",
    "那么什么时候使用外观模式最好？\n",
    "\n",
    "- 在设计阶段，应该有意识的将不同的两个层分离，比如经典的三层架构，需要考虑在数据访问层和业务逻辑层，业务逻辑层和表示层的层与层之间简历外观模式，这样可以为复杂的子系统提供一个简单的接口，使得耦合度降低；\n",
    "- 在开发阶段，子系统往往因为不断重构演化而变得越来越复杂，大多数的模式使用时也都会产生很多很小的类，这本是好事，但是也给外部调用它们的用户程序带来了使用上的困难，增加外观Facade可以提供一个简单的接口，减少它们之间的依赖；\n",
    "- 在维护阶段，可能一个大型的系统已经非常难以维护和扩展，但是因为它包含了重要功能，新的开发需求必须依赖它，此时也可以使用外观模式。可以为新系统开发一个Facade类，来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口，让新系统和Facade对象交互。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
